package com.sunxd.zstudy.proxy.jdk.student;

import com.sunxd.zstudy.proxy.jdk.student.BoyStudent;
import com.sunxd.zstudy.proxy.jdk.student.Student;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author: jdk 动态代理
 * 拿到接口的类（即父类），然后通过jdk的proxy 动态创建子类的代理类,然后用父类调用执行方法
 *
 * 源码阅读： 入口在  Proxy.newProxyInstance
 * 流程： Proxy
 *      拿到当前的所有接口 -》
 *      拿到当前类的class ->
 *      getProxyClass0(生成代理对象 （ProxyClassFactory。apply方法）)
 *             ProxyClassFactory#apply:
 *                  计算包名
 *                  计算生成的代理对象名 $proxy#0
 *                  ProxyGenerator.generateProxyClass 生成字节码数组
 *                          ProxyGenerator#generateProxyClass(java.lang.String, java.lang.Class[], int)
 *                              generateClassFile（填充构造器，方法 等）
 *                  native defineClass0 生成文件
 *       cl.getConstructor（InvocationHandler.class ） 。拿到构造器（Proxy类的）
 *       cons.newInstance(new Object[]{h}) 创建代理对象
 *.
 *
 * *** student.study(); 这里执行的时候，实际调用的是代理类里面的方法
 *     public final String study() throws  {
 *         try {
 *             return (String)super.h.invoke(this, m3, (Object[])null);
 *         } catch (RuntimeException | Error var2) {
 *             throw var2;
 *         } catch (Throwable var3) {
 *             throw new UndeclaredThrowableException(var3);
 *         }
 *     }
 *
 *
 *     super.h  使我们传入的InvocationHandler方法
 *     所以执行的时候，使我们传入的InvocationHandler方法,然后再调用method.invoke(boyStudent, args1)(原始类的方法)
 *
 *
 * @date: 2021-04-10 16:03
 **/
public class Test {


    public static void main(String[] args) {
    System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        BoyStudent boyStudent = new BoyStudent();
        Student student = (Student) Proxy.newProxyInstance(BoyStudent.class.getClassLoader(), BoyStudent.class.getInterfaces(), (proxy, method, args1) -> {
            System.out.println("代理的方法:" + method.getName());
            System.out.println("代理执行开始：可以执行自己的逻辑" );
            Object o = method.invoke(boyStudent, args1);
            System.out.println("代理执行结束：拿到返回值" + o);
            return o;
        });
        student.study();
        System.out.println("代理生成的对象1：" + student.getClass().getName());
    }
}
